package com.cyzy.Handler;

import com.cyzy.dto.DanmakuRequest;
import com.cyzy.service.DanmakuService;
import jakarta.annotation.Resource;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import org.json.JSONObject;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class DanmakuWebSocketHandler extends TextWebSocketHandler {

    // 存储会话与班级ID的映射关系
    private static final Map<String, String> sessionClassMap = new ConcurrentHashMap<>();

    // 存储班级ID与会话的映射关系，用于按班级广播
    private static final Map<String, Map<String, WebSocketSession>> classSessions = new ConcurrentHashMap<>();

    @Resource
    private DanmakuService danmakuService;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        // 从会话属性中获取classId（由DanmakuHandshakeInterceptor设置）
        String classId = (String) session.getAttributes().get("classId");
        String sessionId = session.getId();

        if (classId != null && !classId.isEmpty()) {
            // 存储会话与班级ID的映射
            sessionClassMap.put(sessionId, classId);

            // 将会话添加到班级会话映射中
            classSessions.computeIfAbsent(classId, k -> new ConcurrentHashMap<>())
                    .put(sessionId, session);

            System.out.println("新客户端连接 [" + classId + "]: " + sessionId);

            sendMessageToSession(session, createResponse("danmaku", "连接成功", "欢迎加入班级[" + classId + "]的弹幕互动！"));
        } else {
            // 如果没有班级ID，关闭连接并发送原因
            System.out.println("新客户端连接但未提供班级ID: " + sessionId);
            session.close(CloseStatus.POLICY_VIOLATION.withReason("未提供班级ID"));
        }
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        String sessionId = session.getId();
        String classId = sessionClassMap.get(sessionId);
        String payload = message.getPayload();


        System.out.println("收到消息: " + payload + " from " + sessionId + " (classId: " + classId + ")");

        if (classId == null || classId.isEmpty()) {
            String errorMsg = "无法处理消息，未找到班级ID";
            System.out.println(errorMsg + ": " + payload);
            sendMessageToSession(session, createResponse("error", errorMsg, null));
            return;
        }

        try {
            JSONObject json = new JSONObject(payload);

            // 验证必要字段
            if (!json.has("content") || !json.has("user")) {
                sendMessageToSession(session, createResponse("error", "消息格式错误，缺少必要字段", null));
                return;
            }

            // 创建DanmakuRequest并设置班级ID
            DanmakuRequest request = new DanmakuRequest();
            request.setContent(json.getString("content"));
            request.setUserName(json.getString("user"));
            request.setClassId(classId);

            // 如果消息中包含toUserid字段，则设置
            if (json.has("toUserid")) {
                request.setToUserid(json.getInt("toUserid"));
            }

            System.out.println("收到用户[" + request.getUserName() + (request.getToUserid() != null ? "->" + request.getToUserid() : "") + "]的弹幕内容: " + request.getContent() + "（班级: " + classId + "）");
            // 广播收到的弹幕给同班级所有用户
            JSONObject broadcastMsg = new JSONObject();
            broadcastMsg.put("type", "danmaku");
            broadcastMsg.put("user", json.getString("user"));
            broadcastMsg.put("content", json.getString("content"));
            broadcastMsg.put("timestamp", System.currentTimeMillis());

            // 添加toUserid字段
            if (json.has("toUserid")) {
                broadcastMsg.put("toUserid", json.getInt("toUserid"));
            }

            broadcast(classId, broadcastMsg.toString());
            System.out.println("已向班级[" + classId + "]广播弹幕: " + json.getString("content"));

            // 2. 异步处理AI回复，避免阻塞主线程
            new Thread(() -> {
                try {
                    String response = danmakuService.processDanmaku(request);

                    // 如果有AI回复，广播给同班级所有用户
                    if (response != null && !response.isEmpty()) {
                        JSONObject aiReplyMsg = new JSONObject();
                        aiReplyMsg.put("type", "ai_reply");
                        aiReplyMsg.put("content", response);
                        aiReplyMsg.put("timestamp", System.currentTimeMillis());

                        broadcast(classId, aiReplyMsg.toString());
                        System.out.println("已向班级[" + classId + "]广播AI回复: " + response);
                    }
                } catch (Exception e) {
                    String errorMsg = "处理AI回复出错: " + e.getMessage();
                    System.err.println(errorMsg);
                    e.printStackTrace();
                    try {
                        sendMessageToSession(session, createResponse("error", errorMsg, null));
                    } catch (Exception ex) {
                        // 处理发送错误消息时的异常
                        System.err.println("发送错误消息失败: " + ex.getMessage());
                    }
                }
            }).start();

        } catch (Exception e) {
            String errorMsg = "处理消息出错: " + e.getMessage();
            System.err.println(errorMsg);
            e.printStackTrace();
            sendMessageToSession(session, createResponse("error", errorMsg, null));
        }
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        String sessionId = session.getId();
        String classId = sessionClassMap.get(sessionId);

        System.out.println("客户端断开连接: " + sessionId + " (classId: " + classId + ")");

        // 清理会话映射
        sessionClassMap.remove(sessionId);

        // 从班级会话映射中移除
        if (classId != null && classSessions.containsKey(classId)) {
            classSessions.get(classId).remove(sessionId);
            System.out.println("班级[" + classId + "]剩余连接数: " + classSessions.get(classId).size());

            // 如果班级没有会话了，可以移除整个班级条目
            if (classSessions.get(classId).isEmpty()) {
                classSessions.remove(classId);
                System.out.println("班级[" + classId + "]已无连接，移除该班级");
            }
        }
    }

    // 发送消息到指定会话的工具方法
    private void sendMessageToSession(WebSocketSession session, String message) {
        if (session == null || !session.isOpen()) {
            System.err.println("无法发送消息，会话不存在或已关闭");
            return;
        }

        try {
            session.sendMessage(new TextMessage(message));
            System.out.println("已发送消息到会话[" + session.getId() + "]: " + message);
        } catch (IOException e) {
            System.err.println("发送消息到会话[" + session.getId() + "]失败: " + e.getMessage());
        }
    }

    // 按班级广播消息的方法
    public static void broadcast(String classId, String message) {
        if (classId == null || !classSessions.containsKey(classId)) {
            System.out.println("无法广播消息，班级[" + classId + "]不存在或无连接");
            return;
        }

        Map<String, WebSocketSession> sessions = classSessions.get(classId);
        System.out.println("开始向班级[" + classId + "]的" + sessions.size() + "个连接广播消息");

        // 向班级内所有会话发送消息
        for (WebSocketSession session : sessions.values()) {
            if (session.isOpen()) {
                try {
                    session.sendMessage(new TextMessage(message));
                } catch (IOException e) {
                    System.err.println("向会话[" + session.getId() + "]广播消息失败: " + e.getMessage());
                }
            } else {
                System.out.println("会话[" + session.getId() + "]已关闭，跳过广播");
            }
        }
    }
    public static void oneuser(String to, String message, String toUserid) {
    }

    // 创建标准化响应消息
    private String createResponse(String type, String content, String extra) {
        JSONObject response = new JSONObject();
        response.put("type", type);
        response.put("content", content);
        response.put("timestamp", System.currentTimeMillis());
        if (extra != null) {
            response.put("extra", extra);
        }
        return response.toString();
    }
}
